/**
 * Computer Graphics Lecture WS 2009/2010 Ulm University
 * Creator: Manuel Finckh
 * Email:   manuel.finckh@uni-ulm.de
 */

#include <iostream>
#include <fstream>
#include <omp.h>
#include "cam.h"
#include "scene.h"
#include "render.h"
#include "utils/vec.h"
#include "utils/fileio.h"
#include "utils/MersenneTwister.h"

Render *render;
Cam *cam;

int shader = 2;
int ResX = 300;
int ResY = 300;
#define INTERACTIVE

#ifdef INTERACTIVE
#include <SDL/SDL.h>
#include <SDL_opengl.h>

bool finished = false;
int snapshot = 0;
int samples = 0;

SDL_Surface *screen;
void initScreen(int ResX, int ResY) {
  SDL_Init(SDL_INIT_VIDEO);
  SDL_SetVideoMode(ResX, ResY, 32, SDL_OPENGL | SDL_GL_DOUBLEBUFFER);
}

void clear(){
	Vec3 sum(0.0);
	for(int i = 0; i<ResX*ResY; i++)
		render->image[i] = Vec3(0.0);
}

void intensity(){
	Vec3 sum(0.0);
	for(int i = 0; i<ResX*ResY; i++)
		sum += (render->image[i] / (ResX*ResY));
	sum.printVec3();
}


void eventHandling() {
  SDL_Event event;
  while ( SDL_PollEvent(&event) ) {
    switch ( event.type ) {
      case SDL_KEYDOWN:
        switch ( event.key.keysym.sym ) {
          case SDLK_ESCAPE: finished = true; break;
          case SDLK_q: finished = true; break;
          case SDLK_w: cam->cam_w(true); break;
          case SDLK_a: cam->cam_a(true); break;
          case SDLK_s: cam->cam_s(true); break;
          case SDLK_d: cam->cam_d(true); break;
          case SDLK_c: for(int i = 0; i<ResX*ResY; i++) render->image[i] = Vec3(0.0); break;
	  case SDLK_i: intensity(); break;
          case SDLK_0: shader = 0; render->accum_index = 0;  samples = 0; clear(); break;
          case SDLK_1: shader = 1; render->accum_index = 0;  samples = 0; clear(); break;
          case SDLK_2: shader = 2; render->accum_index = 0;  samples = 0; clear(); break;
          case SDLK_3: shader = 3; render->accum_index = 0;  samples = 0; clear(); break;
          case SDLK_4: shader = 4; render->accum_index = 0;  samples = 0; clear(); break;
          case SDLK_5: shader = 5; render->accum_index = 0;  samples = 0; clear(); break;
          case SDLK_6: shader = 6; render->accum_index = 0;  samples = 0; clear(); break;
          default: break;
        }
        break;
      case SDL_KEYUP:
        switch ( event.key.keysym.sym ) {
          case SDLK_w: cam->cam_w(false); break;
          case SDLK_a: cam->cam_a(false); break;
          case SDLK_s: cam->cam_s(false); break;
          case SDLK_d: cam->cam_d(false); break;
          case SDLK_t: snapshot = 1; break;
          default: break;
        }
        break;
      case SDL_MOUSEMOTION:
        if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(1)) {
          cam->cam_rx(event.motion.yrel);
          cam->cam_ry(event.motion.xrel);
          break;
        }
        break;
      case SDL_QUIT: finished = true; break;
      default: break;
    }
  }
}

#endif

Vec3 *buffer;

int main(int argc, char **argv) {
  Scene *scene;
  if (argc == 2) scene = new Scene(argv[1],ResX,ResY);
  else scene = new Scene("scene/ulmBox_new12.ra2",ResX,ResY);
  scene->loadEnvironment("glacier.hdr");
 
  cam = scene->cam;
  //cam->ResX = ResX;
  //cam->ResY = ResY;
  
  render = new Render(scene);
  
  // just for illustration how the MersenneTwister pseudo random number generator is used
  MTRand *drand = new MTRand(1337); // the initialisation is arbitrary, but never initialize randomly (i.e. time or /dev/ramdom), this would make
                                    // debugging much more complicated (i.e. during rendering a certain sequence of random numbers generates
                                    // a ray which results in a segmentation fault during ray traversal -> this can not be debugged with
                                    // a randomly initialized PRNG.



#ifdef INTERACTIVE
  initScreen(ResX, ResY);
  char title[256];
  float fps = 0.0f;
  int frame = 0;
  unsigned int t0 = SDL_GetTicks();
  float *buffer = new float[render->ResX * render->ResY * 3]; // for tonemapping
  float *image = (float*)render->image;
	 
  while ( !finished ) {
    eventHandling();
    cam->cam_move();
    if(cam->moved){
	samples=0;
    }

    samples++;
    render->render(shader, snapshot);
		
	     //float *image = (float*)render->image;
	     for ( int i = 0; i < ResX * ResY * 3; i++ ){
	     	buffer[i] = image[i] / (1.0f + image[i]);
	     }
	     //(float*)render->image
	    glDrawPixels(ResX, ResY, GL_RGB, GL_FLOAT, buffer);
	    SDL_GL_SwapBuffers();
	    sprintf(title, "%g fps | %d samples", fps, samples);
	    SDL_WM_SetCaption(title, NULL);
	    unsigned int t1 = SDL_GetTicks();
	    frame++;
	    
	    if (t1 - t0 > 500.0f) {
	      fps = 1000.0f / (t1 - t0) * frame;
	      t0 = t1;
	      frame = 0;
	    }
   }
#else
  render->render(shader);
#endif
  
  save_image_ppm("image.ppm", (float*)buffer, ResX, ResY);

  return 0;
}


